﻿#region License statement
// NJamb, a specification and delta-specification DSL
// Copyright (c) 2010-2011, Mark Knell
// Published under the MIT License; all other rights reserved
#endregion

#region using...
using System;
using System.Collections.Generic;
using System.Linq;
using NJamb.NUnit;
using NJamb.Parser.SpecificationBuilders.SubjectIs.Simple.Enumerable;
using NJamb.Parser.SubjectBuilders;
using NJamb.Specifications.Simple.Enumerable;
using NUnit.Framework;
using Stile.Patterns.SelfDescribingPredicates;
#endregion

namespace NJamb.Tests.Specifications.Simple.Enumerable
{
    [TestFixture]
    public class EnumerableAcceptanceTests : EvaluatingSampleFixture
    {
        [Test]
        public void All()
        {
            // arrange
            _sample.AddToEnumerable(7);
            _sample.AddToEnumerable(8);
            _sample.AddToEnumerable(7);
            Assert.That(_sample.IntEnumerable.Count(x => x != 7), Is.EqualTo(1), "precondition");
            Assert.That(_sample.IntEnumerable.Count(x => x == 7), Is.EqualTo(2), "precondition");

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.All.ItemsSatisfying(x => x == 7);

            // assert
            AssertEvaluationFailed(enumerableSpecification.Evaluate(),
                "expected _sample.IntEnumerable would have all 3 items satisfying x => x == 7" + Environment.NewLine
                + " but had only 2 such items. These failed:\r\nList<int> {8}.");
        }

        [Test]
        public void NoItemsSatisfying()
        {
            CollectionAssert.IsEmpty(_sample.IntEnumerable, "precondition");

            // arrange
            IEnumerableSpecification<IEnumerable<int>, int> specification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.No.ItemsSatisfying(x => 1 == x);

            // act
            IEvaluation evaluation = specification.Evaluate();

            // assert
            Assert.IsNotNull(evaluation);
            Assert.IsTrue(evaluation.Success);
        }

        [Test]
        public void One()
        {
            // arrange
            _sample.AddToEnumerable(7);
            _sample.AddToEnumerable(7);
            Assert.That(_sample.IntEnumerable.Count(x => x == 7), Is.EqualTo(2));

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.One.ItemsSatisfying(x => x == 7);

            // assert
            AssertEvaluationFailed(enumerableSpecification.Evaluate(),
                "expected _sample.IntEnumerable would have one item satisfying x => x == 7" + Environment.NewLine
                + " but had 2 such items.");
        }

        [Test]
        public void Sequence()
        {
            // arrange
            INegatableEnumerableIs<IEnumerable<int>, int> negatableEnumerableIs =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Is;

            // act
            IEnumerableSpecification<IEnumerable<int>, int> enumerableSpecification = negatableEnumerableIs.Empty;

            // assert
            IEvaluation evaluation = enumerableSpecification.Evaluate();
            Assert.That(evaluation.Success, Is.True);
        }

        [Test]
        public void SomeItemsSatisfying()
        {
            CollectionAssert.IsEmpty(_sample.IntEnumerable, "precondition");

            // arrange
            IEnumerableSpecification<IEnumerable<int>, int> specification =
                Specify.For(() => _sample).ThatTheSequence(x => x.IntEnumerable).Has.Some.ItemsSatisfying(x => 1 == x);

            // act
            IEvaluation evaluation = specification.Evaluate();

            // assert
            Assert.That(evaluation.Success, Is.False);
            Assert.That(evaluation.Reason,
                Is.EqualTo("expected _sample.IntEnumerable would have some items satisfying x => 1 == x" + Environment.NewLine
                           + " but had 0 such items."));
        }
    }
}
